/* ==================================================================== *
 *
 * This file is part of Mapics Framework.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author Andrey Cherkashin <action.open@gmail.com>
 *
 * ==================================================================== */

/**
 * Class to make map layer by Google Maps API.
 *
 * @package mapics
 * @static
 * @author Andrey Cherkashin <action.open@gmail.com>
 */
mapics.MapLayerGoogle = function()
{
    // Map overlay levels
    this.m_Overlays = {};

    // Map event listeners
    this.m_Listeners = [];
};

/**
 * Inheritance from MapLayer class
 */
mapics.MapLayerGoogle.prototype = new mapics.MapLayer();

/** ------------------------------------------------------------------------- **
 *  ACTIONS
 ** ------------------------------------------------------------------------- **/

/**
 * Shows Google Map in specific div by loading specific privider JS file using
 * AJAX. After that, calls callback function.
 *
 * @param mapDiv   (HTMLObject) Div for map layer
 * @param complete (Callback) Callback function
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerGoogle.prototype.show = function( mapDiv, complete )
{
    var self = this;

    // Save map div
    this.m_MapDiv = mapDiv;

    // Predefine callback function on script loading success
    callbackGoogle = function()
    {
        // Creating maps
        self.m_Map = new google.maps.Map(
            mapDiv, {
                zoom: 12,
                center: new google.maps.LatLng(55.75806608183598, 37.632576003670714),
                disableDefaultUI: true,
                disableDoubleClickZoom: true,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            }
        );

        // Clear for ourselves =)
        delete callbackGoogle;

        // Callback
        if( complete ) {
            complete();
        }
    };

    if( !mapics.requestJS("http://maps.google.com/maps/api/js?v=3&sensor=false&callback=callbackGoogle") ) {
        callbackGoogle();
    }

    return this;
};

/**
 * Hides Google map and destroy layer
 *
 * @return mapics.MapLayerGoogle
 */
mapics.MapLayerGoogle.prototype.hide = function()
{
    if( this.m_Map ) {
        this.m_Map.getDiv().innerHTML = "";
        delete this.m_Map;
    }

    return this;
};

/**
 * Smooth move map to specific coordinates
 *
 * @param center {
 *     'lat': (double) Latitude,
 *     'lng': (double) Longitude
 * }
 *
 * @return mapics.MapLayerGoogle
 */
mapics.MapLayerGoogle.prototype.panTo = function(center)
{
    this.m_Map.panTo( new google.maps.LatLng(center.lat, center.lng) );
    return this;
};

/**
 * Adds event listener on some event with that map layer
 *
 * @param eventName (string) Mapics Event name
 * @param handler   (function) Event Handler
 *
 * @return mapics.MapEventListener
 */
mapics.MapLayerGoogle.prototype.addListener = function(eventName, handler)
{
    var event;
    
    switch(eventName) {
        case "idle": event = "idle";    break;
        default:     event = eventName; break;
    }

    // Create google's listener
    var listenerGoogle = google.maps.event.addListener(this.m_Map, event, handler);

    // Return our listener
    return ( this.m_Listeners[ this.m_Listeners.length ] = new mapics.MapEventListener(eventName, listenerGoogle, handler) );
};

/**
 * Removes event listener from that map layer
 *
 * @param eventListener (mapics.MapEventListener)
 *
 * @return mapics.MapLayer
 */
mapics.MapLayerGoogle.prototype.removeListener = function(eventListener)
{
    // Remove google listener
    google.maps.event.removeListener(eventListener.getListener());

    for(var i = 0, max = this.m_Listeners.length; i < max; i++)
    {
        if( this.m_Listeners[i] == eventListener ) {
            this.m_Listeners.splice(i, 1);
            break;
        }
    }

    eventListener.setListener(null);

    return this;
};

/** ------------------------------------------------------------------------- **
 *  AGGREGATION
 ** ------------------------------------------------------------------------- **/

/**
 * Returns this map layer's overlay by specific level
 *
 * @param level (int) Z-Index for this overlay
 *
 * @return mapics.MapLayerGoogleOverlay
 */
mapics.MapLayerGoogle.prototype.getOverlay = function(level)
{
    // Check for existed overlay
    if( this.m_Overlays[level] ) {
        return this.m_Overlays[level];
    }

    // Create new overlay
    this.m_Overlays[level] = new mapics.MapLayerGoogleOverlay(level, this.m_Map);

    return this.m_Overlays[level];
};

/** ------------------------------------------------------------------------- **
 *  PROPERTIES
 ** ------------------------------------------------------------------------- **/

/**
 * Returns current provider name
 *
 * @return string
 */
mapics.MapLayerGoogle.prototype.getProviderName = function() {
    return "google";
};

/**
 * Returns current type of this map layer
 *
 * @see MapLayer constructor's consts: TYPE_*
 *
 * @return int
 */
mapics.MapLayerGoogle.prototype.getType = function()
{
    var typeId = this.m_Map.getMapTypeId();

    switch( typeId )
    {
        case google.maps.MapTypeId.ROADMAP:
            return mapics.MapLayer.TYPE_MAP;
            
        case google.maps.MapTypeId.SATELLITE:
            return mapics.MapLayer.TYPE_SATELLITE;

        case google.maps.MapTypeId.HYBRID:
            return mapics.MapLayer.TYPE_HYBRID;
    }
};

/**
 * Sets current type of this map layer
 *
 * @see MapLayer constructor's consts: TYPE_*
 *
 * @param type (int) New map layer type
 *
 * @return mapics.MapLayerGoogle
 */
mapics.MapLayerGoogle.prototype.setType = function(type)
{
    switch( type )
    {
        case mapics.MapLayer.TYPE_MAP:
            this.m_Map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
            break;
        case mapics.MapLayer.TYPE_SATELLITE:
            this.m_Map.setMapTypeId(google.maps.MapTypeId.SATELLITE);
            break;
        case mapics.MapLayer.TYPE_HYBRID:
            this.m_Map.setMapTypeId(google.maps.MapTypeId.HYBRID);
            break;
    }

    return this;
};

/**
 * Returns current center of this map layer
 *
 * @return {
 *     'lat': (double) Latitude,
 *     'lng': (double) Longitude
 * }
 */
mapics.MapLayerGoogle.prototype.getCenter = function()
{
    var center = this.m_Map.getCenter();

    return {
        'lat': center.lat(),
        'lng': center.lng()
    };
};

/**
 * Sets current center of this map layer
 *
 * @param center {
 *     'lat': (double) Latitude,
 *     'lng': (double) Longitude
 * }
 *
 * @return mapics.MapLayerGoogle
 */
mapics.MapLayerGoogle.prototype.setCenter = function(center)
{
    this.m_Map.setCenter( new google.maps.LatLng(center.lat, center.lng) );
    return this;
};

/**
 * Returns current zoom of this map layer
 *
 * @return int
 */
mapics.MapLayerGoogle.prototype.getZoom = function() {
    return this.m_Map.getZoom();
};

/**
 * Sets current zoom of this map layer
 *
 * @param zoom (int) Zoom
 *
 * @return mapics.MapLayerGoogle
 */
mapics.MapLayerGoogle.prototype.setZoom = function(zoom)
{
    this.m_Map.setZoom( zoom );
    return this;
};